-
Notifications
You must be signed in to change notification settings - Fork 32
Expose pointer to free from allocators #203
Conversation
Closes: dart-lang/native#910 |
@mraleph How about the interplay of Are we expecting devs to mix and match allocators? using((arena) {
final str = "myString".toNativeUtf8(allocator: arena);
final buf = malloc<Uint8>(len).asTypedList(len, finalizer: malloc.nativeFree);
}); In general we have a question about combining finalizers and eager finalization (dart-lang/sdk#49906), but in this specific case, the native finalizer can't be cancelled, so there's no reason to use the arena for the list backing the typed data. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm with comments.
lib/src/allocation.dart
Outdated
stdlib.lookup('CoTaskMemFree'); | ||
final WinCoTaskMemFree winCoTaskMemFree = winCoTaskMemFreePtr.asFunction(); | ||
|
||
abstract class AllocatorExposingNativeFinalizer implements Allocator { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add interface
keyword.
We could consider making it just a marker interface and not implementing Allocator
and making the allocators types in their own right (then the name would be NativeFreeable
). But having it implement the allocator makes it useful for specifying the type of malloc
and calloc
. So that's probably better.
* Bump version and update CHANGELOG.md
I think this change specifically addresses non-arena based usage, if you have |
cc @lrhn for a potentially better name for lgtm from my side. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All in all, this feels a little to much like a hack, more than a coherent design.
You need a function, so you make the existing class, which happens to know about the function, expose it, in its public API.
I have many ideas for how to completely redesign Allocator
, but a more conservative design would be to expose Malloc
and Calloc
classes (final and with private constructors), and have them expose the native free
function as a static getter.
Then you have
final class Malloc implements Allocator {
Pointer(T) alloc<T>(int count) { ... }
void free(Pointer allocation) { ... }
static final Pointer<NativeFunction<Void Function(Pointer)>> nativeFree = ...;
static final Pointer<NativeFunction<Pointer Function(IntPointer)>> nativeAlloc = ...;
}
// ....
const Malloc malloc = MallocAllocator();
and similarly for CallocAllocator
where nativeAlloc
takes two arguments.
That gives you a link between the Allocator
instance and its functions, without exposing them from the object itself.
Or if you prefer, drop the NativeFreeableAllocator
type, and expose CallocAllocator
and MallocAllocator
types that each have instance getters for nativeFree
and nativeAlloc
, but not shared supertype.
Then you can't abstract over the NativeFreeableAllocator
and get to its nativeFree
, but it's an abstraction that doen't work for alloc
, and which feels glued on the Allocator
API. I'd see if it could work before introducing a shared supertype just for nativeFree
.
Hm, I had the same thought in the comments (but with a marker interface in case someone would want to write generic code).
The use cases that we have don't require a shared super type.
Making a |
I am not sure I like this proposal - it makes the code look strange: final x = malloc.allocate<Uint8>(len).asTypedList(len, finalizer: Malloc.nativeFree); Notice there is
I can do this - I don't think any other major changes are worth it. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please also add a test in test/allocation_test.dart
.
Thanks @mraleph ! |
This enables to write code like this: